﻿using Modbus.Device;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Threading;
using Timer = System.Threading.Timer;

namespace IndustrialControlLibrary
{
    public partial class HMI_Connection : Component
    {
        public HMI_Connection()
        {
            InitializeComponent();
        }

        public HMI_Connection(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
        }


        /// <summary>
        /// 参数准备
        /// </summary>
        /// 
        public static Action GetData_Action;
        public Timer timer = new Timer(new TimerCallback(Execute), null, -1, 200);
        private StopBits serialStopBit = StopBits.One;
        private Parity serialParity = Parity.None;

        private TcpClient client;
        public SerialPort m_serialPort = null;
        public dynamic modbusMaster;

        TagsManager tagsManager;
        public Control FormControls;

        /// <summary>
        /// 执行方法,被timer调用，启动GetData_Action委托
        /// </summary>
        /// <param name="o"></param>
        public static void Execute(object o)
        {
            GetData_Action?.Invoke();
        }


        /// <summary>
        /// 用于绑定委托，然后再去控件显示
        /// </summary>
        /// <param name="controlName"></param>
        /// <param name="isDisplay"></param>
        public void TodisplayValue(string controlName, string value)
        {
            if (FormControls != null)
            {
                ((dynamic)FormControls.Controls.Find(controlName, false)[0]).DisplayValue(value);
            }
        }


        /// <summary>
        /// 连接初始化, 输入，输出控件传值
        /// </summary>
        /// <param name="fatherControl"></param>
        public void ConnectionInit(Control fatherControl)
        {
            #region 初始化连接
            tagsManager = new TagsManager(this.BigOrLittleEndian, this.StoreByteOrder);
            m_serialPort = new SerialPort();
            if (!m_serialPort.IsOpen)
            {
                try
                {
                    if (this.ConnectWay.ToString() == "ModbusTCP")
                    {
                        client = new TcpClient();
                        client.Connect(this.IPAddress.Trim(), this.IPSlavePort);
                    }
                    else
                    {
                        m_serialPort.PortName = this.SerialPortName;
                        m_serialPort.BaudRate = this.SerialBaudRate;
                        m_serialPort.DataBits = 8;
                        m_serialPort.StopBits = serialStopBit;
                        m_serialPort.Parity = serialParity;

                        m_serialPort.Open();
                    }

                    switch (this.ConnectWay.ToString())
                    {
                        case "ModbusTCP":
                            modbusMaster = ModbusIpMaster.CreateIp(client);
                            break;
                        case "ModbusRTU":
                            modbusMaster = ModbusSerialMaster.CreateRtu(m_serialPort);
                            break;
                        case "ModbusASCII":
                            modbusMaster = ModbusSerialMaster.CreateAscii(m_serialPort);
                            break;

                        default:
                            MessageBox.Show("连接失败，请检查连接方式");
                            return;
                    }

                    modbusMaster.Transport.Retries = 2;
                    modbusMaster.Transport.WriteTimeout = 2000;
                    modbusMaster.Transport.ReadTimeout = 2000;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }

            }
            else
            {
                MessageBox.Show("连接出错");
            }
            MessageBox.Show("connected finish");
            tagsManager.modbusMaster = modbusMaster;
            #endregion

            #region 控件初始化

            FormControls = fatherControl;
            Control.ControlCollection sonControls = fatherControl.Controls;
            //遍历所有HMI控件
            //StringBuilder controlTypeName = new StringBuilder(64);
            string controlTypeName = null;
            var controlLis = new List<Control>();
            foreach (dynamic control in sonControls)
            {
                controlTypeName = control.GetType().Name;
                if (controlTypeName.Substring(0, 3) == "HMI")
                {

                    switch (controlTypeName.Substring(0, 6))
                    {

                        case "HMI_I_":
                            // 控件传入modbusMaster实例
                            control.assignMaster(modbusMaster);
                            break;

                        case "HMI_O_":
                            // 从控件传值到TagList, 然后建立实时显示
                            controlLis.Add(control);
                            break;

                        case "HMI_IO":
                            // 既需要显示，又可以写值
                            break;

                        default:
                            break;
                    }
                }
            }
            tagsManager.controlList = controlLis;    // 获取显示控件control实例
            if (controlLis.Count() > 0)
            {
                tagsManager.toDisplay += TodisplayValue; // 注册显示委托
                GetData_Action = tagsManager.GetData;    // 注册获取数据委托
                timer.Change(0, this.RefreshRate);       // 开始轮询
            }
            MessageBox.Show("init finsh");
            #endregion

        }


        /// <summary>
        /// 断开连接
        /// </summary>
        public void ConnectionDispose()
        {
            timer.Change(-1, -1);
            timer.Dispose();
            if (m_serialPort != null && m_serialPort.IsOpen)
            {
                m_serialPort.Close();
                modbusMaster.Dispose();
            }
        }
    }
}
